home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 43 / Amiga Format CD43 (1999)(Future Publishing)(GB)(Track 1 of 2)[!][issue 1999-09].iso / -serious- / graphics / picfx / e-source / parser.e next >
Text File  |  1999-06-15  |  34KB  |  918 lines

  1. OPT MODULE,LARGE,PREPROCESS
  2.  
  3. MODULE 'amigalib/lists',
  4.        'dos/dos',
  5.        'exec/lists','exec/memory','exec/nodes','exec/ports','exec/semaphores','exec/tasks',
  6.        'graphics/rastport','cybergraphics','picasso96api'
  7.  
  8. MODULE 'tools/debug' -> kputfmt('',[])
  9.  
  10.  
  11. /* Some stuff for picFX... I was forced to put it here, as I couldn't reference the main executable when needing them */
  12.  
  13. EXPORT OBJECT project_Node
  14.     ln:ln   -> base node structure
  15.     window  -> window object
  16.     item    -> string that appears in opened_lst
  17.     pid     -> Project ID
  18. ENDOBJECT
  19.  
  20. EXPORT OBJECT subtaskmsg
  21.    stm_Message:mn
  22.    stm_Command:INT
  23.    stm_Parameter:LONG
  24.    stm_Result:LONG
  25. ENDOBJECT
  26.  
  27. EXPORT OBJECT subtask
  28.   st_Task:PTR TO tc      /* sub task pointer */
  29.   st_Port:PTR TO mp      /* allocated by sub task */
  30.   st_Reply:PTR TO mp     /* allocated by main task */
  31.   st_Data:LONG           /* more initial data to pass to the sub task */
  32.   st_Message:subtaskmsg  /* Message buffer */
  33. ENDOBJECT
  34.  
  35. EXPORT OBJECT planeFunc_data
  36.     projectid -> Project ID, used when referencing a project from "outside"
  37.  
  38.                         /***attributes storage***/
  39.     bfunc:PTR TO expression
  40.     bstr:PTR TO CHAR
  41.     failure                    /*$RGB*/
  42.     gfunc:PTR TO expression
  43.     gstr:PTR TO CHAR
  44.     height
  45.     imagefile:PTR TO CHAR
  46.     left,newleft                ->scroll when newleft is non-zero
  47.     loading
  48.     loadm
  49.     lock -> -1 when there's a writelock, 0 when it is free, number of readlocks otherwise
  50.     name:PTR TO CHAR
  51.     projectnode:PTR TO project_Node
  52.     rfunc:PTR TO expression
  53.     rstr:PTR TO CHAR
  54.     paused -> this is used by the 'state' attribute, with the 'lock' var
  55.     outputr,outputg,outputb
  56.     quiet
  57.     top,newtop                  -> scroll when newtop is non-zero
  58.     type
  59.     width
  60.     xmin,xmax,ymin,ymax         -> area to draw to
  61.                         /***some pointers...***/
  62.     hscroll,vscroll         -> scrollers of the window
  63.     app                     -> pointer to application
  64.     self                    -> pointer to ourselves
  65.                         /***some useful data***/
  66.     savepixel               -> true if the previous pixel must be saved
  67.     line:PTR TO LONG        -> kind of graphic buffer... Cgx only (for now:-)
  68.     rupd                    -> copy of the render-update preference variable.
  69.     sema:ss                 -> data item protection
  70.     subtask:PTR TO subtask  -> our sub task
  71.     rp:PTR TO rastport      -> rastport for the sub task
  72.     drawn                   -> the last line that has been drawn to the window
  73.     calculated              -> the last line that has been calculated by the subtask
  74.     ds:datestamp            -> planeFunc stores the datestamp when a calculation is started
  75. ENDOBJECT
  76.  
  77. EXPORT ENUM OUT_Integer=0, -> 32bits integer
  78.             OUT_Float32, -> 32Bits float
  79.             OUT_Float64,  -> 64Bits float
  80.             OUT_OldR,OUT_OldG,OUT_OldB, -> Components of the pixel (previous calculation!)
  81.             OUT_CopyR,OUT_CopyG          -> Copies the new expression (e.g. black'n'white)
  82.  
  83. /* Function class. This class handles the functions like sin, +, r(), and so on, the old function class has been renamed to expression.
  84. You can easily add functions, just put the evaluation code somewhere (better is to keep the order !) and then put it in initfuncs, in
  85. the same way as the other.*/
  86.  
  87. OBJECT function
  88.     ln:ln
  89.     argcount:LONG
  90.     readpid -> if TRUE: cte::projectid ->-> data
  91.     evalI,evalF:LONG -> address of the evaluating procedures
  92. ENDOBJECT
  93. /* For compatibility with previous versions, a function having a constant will
  94. be read as f(cte,arg1,arg2), and not f(arg1,arg2,cte), as you might think*/
  95.  
  96. EXPORT DEF fconstant,fvariable, -> The addresses of these two function nodes  (!FUNCTION OBJECTS!)
  97.            firstb,lastb:PTR TO ln        -> first & last x_y .     (!LN OBJECTS!)
  98.  
  99. DEF funclist:PTR TO lh,
  100.     gtd,-> gtd is the address of the getdata(dat,num) PROC
  101.     dat -> dat is the address of the ProjectlistObject's data
  102.  
  103. DEF c,p,s -> c,p = number of used A5, respectively by calc and precalc; s is used A1.
  104.  
  105. DEF count,mc,bs, -> precompilation stuff    mc stands for max-count, bs for buffer-size
  106.     code:PTR TO INT,crs:PTR TO INT, -> code is the beginning, crs is the point we are at.
  107.     precalc:PTR TO INT,prs:PTR TO INT,
  108.     buffer                          ->  *temporary* storage of the current buffer (*copy* of self.buffer, the address)
  109.  
  110. PROC create(name,argcount,evalI,evalF) OF function
  111.     self.ln.name:=String(StrLen(name))
  112.     StrCopy(self.ln.name,name)
  113.     self.argcount:=argcount
  114.     self.evalI:=evalI
  115.     self.evalF:=evalF
  116. ENDPROC
  117.  
  118. PROC end() OF function
  119.     DisposeLink(self.ln.name)
  120. ENDPROC
  121.  
  122. EXPORT PROC initfuncs(gtda,data,picasso)
  123. DEF thatfunc:PTR TO function,k:PTR TO function
  124.  
  125.     gtd:=gtda
  126.     dat:=data
  127.  
  128.     NEW funclist
  129.     newList(funclist)
  130.  
  131.     NEW thatfunc.create('Constant',0,{e_constant},{e_constant})
  132.     AddTail(funclist,thatfunc.ln)
  133.     fconstant:=thatfunc
  134.                                                        
  135.     NEW thatfunc.create('Variable',0,{e_variable},{e_variable})
  136.     AddTail(funclist,thatfunc.ln)
  137.     fvariable:=thatfunc
  138.  
  139. /*Following functions are sorted by order of priority*/
  140.  
  141.     NEW thatfunc.create('%',2,{e_mod},{f_mod})
  142.     AddTail(funclist,thatfunc.ln)
  143.     firstb:=thatfunc.ln -> This is the first x_y style operator
  144.  
  145.     NEW thatfunc.create('+',2,{e_add},{f_add})
  146.     AddTail(funclist,thatfunc.ln)
  147.  
  148.     NEW thatfunc.create('-',2,{e_sub},{f_sub})
  149.     AddTail(funclist,thatfunc.ln)
  150.  
  151.     NEW thatfunc.create('*',2,{e_mul},{f_mul})
  152.     AddTail(funclist,thatfunc.ln)
  153.  
  154.     NEW thatfunc.create('/',2,{e_div},{f_div})
  155.     AddTail(funclist,thatfunc.ln)
  156.  
  157.     NEW thatfunc.create('^',2,{e_pow},{f_pow})
  158.     AddTail(funclist,thatfunc.ln)
  159.     lastb:=thatfunc.ln -> this is the last x_y style operator
  160.  
  161.     NEW thatfunc.create('abs',1,{e_abs},{f_abs})
  162.     AddTail(funclist,thatfunc.ln)
  163.  
  164.     NEW thatfunc.create('neg',1,{e_neg},{f_neg}) -> '-a' is possible but slower than 'neg(a)', because interpreted as '0-a'
  165.     AddTail(funclist,thatfunc.ln)
  166.  
  167.     NEW thatfunc.create('cos',1,{e_constant},{f_cos}) -> return zero for int32 :-)
  168.     AddTail(funclist,thatfunc.ln)
  169.  
  170.     NEW thatfunc.create('sin',1,{e_constant},{f_sin})
  171.     AddTail(funclist,thatfunc.ln)
  172.  
  173.     NEW thatfunc.create('tan',1,{e_constant},{f_tan})
  174.     AddTail(funclist,thatfunc.ln)
  175.  
  176.     NEW thatfunc.create('acos',1,{e_constant},{f_acos})
  177.     AddTail(funclist,thatfunc.ln)
  178.  
  179.     NEW thatfunc.create('asin',1,{e_constant},{f_asin})
  180.     AddTail(funclist,thatfunc.ln)
  181.  
  182.     NEW thatfunc.create('atan',1,{e_constant},{f_atan})
  183.     AddTail(funclist,thatfunc.ln)
  184.  
  185.     NEW thatfunc.create('angle',2,{e_constant},{f_angle})
  186.     AddTail(funclist,thatfunc.ln)
  187.  
  188.     NEW thatfunc.create('min',2,{e_min},{f_min})
  189.     AddTail(funclist,thatfunc.ln)
  190.  
  191.     NEW thatfunc.create('max',2,{e_max},{f_max})
  192.     AddTail(funclist,thatfunc.ln)
  193.  
  194.     NEW thatfunc.create('sqrt',1,{e_sqrt},{f_sqrt})
  195.     AddTail(funclist,thatfunc.ln)
  196.  
  197.     NEW thatfunc.create('ln',1,{e_ln},{f_ln})
  198.     AddTail(funclist,thatfunc.ln)
  199.  
  200.     NEW thatfunc.create('log',2,{e_log},{f_log})
  201.     AddTail(funclist,thatfunc.ln)
  202.  
  203.     NEW thatfunc.create('cosh',1,{e_constant},{f_cosh}) -> maybe later, approximated int value?
  204.     AddTail(funclist,thatfunc.ln)
  205.  
  206.     NEW thatfunc.create('sinh',1,{e_constant},{f_sinh})
  207.     AddTail(funclist,thatfunc.ln)
  208.  
  209.     NEW thatfunc.create('tanh',1,{e_constant},{f_tanh})
  210.     AddTail(funclist,thatfunc.ln)
  211.  
  212.     NEW thatfunc.create('acosh',1,{e_constant},{e_constant})->,{f_acosh})
  213.     AddTail(funclist,thatfunc.ln)                      
  214.                                                        
  215.     NEW thatfunc.create('asinh',1,{e_constant},{e_constant})->,{f_asinh})
  216.     AddTail(funclist,thatfunc.ln)                      
  217.                                                        
  218.     NEW thatfunc.create('atanh',1,{e_constant},{e_constant})->,{f_atanh})
  219.     AddTail(funclist,thatfunc.ln)
  220.  
  221.     IF picasso
  222.         NEW thatfunc.create('r',3,{p_red},{q_red})
  223.         thatfunc.readpid:=TRUE
  224.         AddTail(funclist,thatfunc.ln)
  225.         NEW thatfunc.create('g',3,{p_green},{q_green})
  226.         thatfunc.readpid:=TRUE
  227.         AddTail(funclist,thatfunc.ln)
  228.         NEW thatfunc.create('b',3,{p_blue},{q_blue})
  229.         thatfunc.readpid:=TRUE
  230.         AddTail(funclist,thatfunc.ln)
  231.     ELSE -> Cyber
  232.         NEW thatfunc.create('r',3,{e_red},{f_red})
  233.         thatfunc.readpid:=TRUE
  234.         AddTail(funclist,thatfunc.ln)
  235.         NEW thatfunc.create('g',3,{e_green},{f_green})
  236.         thatfunc.readpid:=TRUE
  237.         AddTail(funclist,thatfunc.ln)
  238.         NEW thatfunc.create('b',3,{e_blue},{f_blue})
  239.         thatfunc.readpid:=TRUE
  240.         AddTail(funclist,thatfunc.ln)
  241.     ENDIF
  242. ENDPROC
  243.  
  244. EXPORT PROC cleanfuncs()
  245. DEF thisnode:PTR TO ln,nextone
  246.  
  247.     thisnode:=funclist.head
  248.     WHILE (nextone:=thisnode.succ) AND Not(CtrlC()) -> Destroy all functions...
  249.         DisposeLink(thisnode.name)
  250.         END thisnode;thisnode:=nextone
  251.     ENDWHILE
  252.     END funclist
  253. ENDPROC
  254.  
  255. /* I am required to have the three arguments, so I cannot get rid of the unreferenced messages.*/
  256.  
  257. PROC e_constant(x,y,c) IS c
  258.  
  259. ENUM VAR_x,VAR_y
  260. PROC e_variable(x,y,c)
  261.     IF c=VAR_x THEN RETURN x
  262. ENDPROC y
  263. PROC f_variable(x,y,c) -> Test: Let's use the above one instead and have picFX convert the vars...
  264.     IF c=VAR_x THEN RETURN x!
  265. ENDPROC y!
  266.  
  267. EXPORT PROC e_mod(x,y,c=0) -> This is also used in picFX as a kind of replacement to Mod()
  268.     IF y = 0; RETURN 0
  269.     ELSEIF x >= 0; RETURN Mod(x,y)
  270.     ENDIF
  271. ENDPROC Mod(x,y)+y
  272. PROC f_mod(x,y,c)
  273.     IF y = 0. THEN RETURN 0.
  274. ENDPROC !x-(!Ffloor(!x/y)*y)
  275.  
  276. PROC e_add(x,y,c) IS x+y
  277. PROC f_add(x,y,c) IS !x+y
  278.  
  279. PROC e_sub(x,y,c) IS x-y
  280. PROC f_sub(x,y,c) IS !x-y
  281.  
  282. PROC e_mul(x,y,c) IS Mul(x,y)
  283. PROC f_mul(x,y,c) IS !x*y
  284.  
  285. PROC e_div(x,y,c)
  286.     IF y = 0 THEN RETURN 123456 ELSE RETURN Div(x,y)
  287. ENDPROC
  288.  
  289. PROC f_div(x,y,c)
  290.     IF y = 0. THEN RETURN 123456. ELSE RETURN !x/y
  291. ENDPROC
  292.  
  293. PROC e_pow(x,y,c) -> maybe would be quicker to convert to float, power, and back to int again?
  294. DEF result
  295.     IF y = 0 THEN RETURN 1
  296.     result:=x
  297.     WHILE y > 1
  298.         result:=Mul(result,x)
  299.         y--
  300.     ENDWHILE
  301. ENDPROC result
  302. PROC f_pow(x,y,c) IS Fpow(y,x)
  303.  
  304. PROC e_abs(x,y,c) IS Abs(x)
  305. PROC f_abs(x,y,c) IS Fabs(x)
  306.  
  307. PROC e_neg(x,y,c) IS -x
  308. PROC f_neg(x,y,c) IS !-x
  309.  
  310. PROC f_sin(x,y,c) IS Fsin(x)
  311. PROC f_cos(x,y,c) IS Fcos(x)
  312. PROC f_tan(x,y,c) IS Ftan(x) -> I don't know if we can pass pi/2 to this function. But as it is approximated, it shouldn't cause problems...
  313. PROC f_asin(x,y,c) IS Fasin(x)
  314. PROC f_acos(x,y,c) IS Facos(x)
  315. PROC f_atan(x,y,c) IS Fatan(x)
  316.  
  317. PROC f_angle(x,y,c)
  318.     IF y=0.
  319.         IF x<0. THEN RETURN 3.14159265 ELSE RETURN 0.
  320.     ELSEIF !y<0
  321.         RETURN !Fatan(!x/y)+1.5707963
  322.     ENDIF
  323. ENDPROC !Fatan(!x/y)-1.5707963
  324.  
  325. PROC e_min(x,y,c) IS Min(x,y)
  326. PROC f_min(x,y,c)
  327.     IF !x>y THEN RETURN y ELSE RETURN x
  328. ENDPROC
  329.  
  330. PROC e_max(x,y,c) IS Max(x,y)
  331. PROC f_max(x,y,c)
  332.     IF !x<y THEN RETURN y ELSE RETURN x
  333. ENDPROC
  334.  
  335. PROC e_sqrt(x,y,c) IS !Fsqrt(x!)!
  336. PROC f_sqrt(x,y,c) IS Fsqrt(x)
  337.  
  338. PROC e_ln(x,y,c)
  339.     IF x <= 0 THEN RETURN 123456 ELSE RETURN !Flog(x!)!
  340. ENDPROC
  341. PROC f_ln(x,y,c)
  342.     IF x<=0 THEN RETURN 123456. ELSE RETURN Flog(x)
  343. ENDPROC
  344.  
  345. PROC e_log(x,y,c) -> All these tests are annoying, but I do not know how to avoid them...
  346.     IF (x<=0) OR (y<=0) OR (y=1) THEN RETURN 123456 ELSE RETURN !Flog(x!)/Flog(y!)!
  347. ENDPROC
  348. PROC f_log(x,y,c)
  349.     IF (x<=0.) OR (y<=0.) OR (y=1. ) THEN RETURN 123456. ELSE RETURN !Flog(x)/Flog(y)
  350. ENDPROC
  351.  
  352. PROC f_sinh(x,y,c) IS !Fcosh(x)*Ftanh(x) -> Fsinh(x) -> I am doing something wrong somewhere, anyway putting fsinh causes a crash...
  353. PROC f_cosh(x,y,c) IS Fcosh(x)
  354. PROC f_tanh(x,y,c) IS Ftanh(x)
  355.  
  356. /*PROC f_asinh(x,y,c) IS Fasinh(x) -> These three aren't implemented in E...
  357. PROC f_acosh(x,y,c) IS Facosh(x)
  358. PROC f_atanh(x,y,c) IS Fatanh(x)*/
  359.  
  360. PROC e_red(x,y,c:PTR TO planeFunc_data) IS Shr(ReadRGBPixel(c.rp,e_mod(x,c.width),e_mod(y,c.height)),16)
  361. PROC f_red(x,y,c:PTR TO planeFunc_data) IS Shr(ReadRGBPixel(c.rp,e_mod(!x!,c.width),e_mod(!y!,c.height,0)),16)!
  362.  
  363. PROC e_green(x,y,c:PTR TO planeFunc_data) IS Shr(ReadRGBPixel(c.rp,e_mod(x,c.width),e_mod(y,c.height)),8) AND $FF
  364. PROC f_green(x,y,c:PTR TO planeFunc_data) IS (Shr(ReadRGBPixel(c.rp,e_mod(!x!,c.width),e_mod(!y!,c.height)),8) AND $FF)!
  365.  
  366. PROC e_blue(x,y,c:PTR TO planeFunc_data) IS ReadRGBPixel(c.rp,e_mod(x,c.width),e_mod(y,c.height)) AND $FF
  367. PROC f_blue(x,y,c:PTR TO planeFunc_data) IS (ReadRGBPixel(c.rp,e_mod(!x!,c.width),e_mod(!y!,c.height)) AND $FF)!
  368.  
  369. PROC p_red(x,y,c:PTR TO planeFunc_data) IS Shr(Pi96ReadPixel(c.rp,e_mod(x,c.width),e_mod(y,c.height)),16)
  370. PROC q_red(x,y,c:PTR TO planeFunc_data) IS Shr(Pi96ReadPixel(c.rp,e_mod(!x!,c.width),e_mod(!y!,c.height)),16)!
  371.  
  372. PROC p_green(x,y,c:PTR TO planeFunc_data) IS Shr(Pi96ReadPixel(c.rp,e_mod(x,c.width),e_mod(y,c.height)),8) AND $FF
  373. PROC q_green(x,y,c:PTR TO planeFunc_data) IS (Shr(Pi96ReadPixel(c.rp,e_mod(!x!,c.width),e_mod(!y!,c.height)),8) AND $FF)!
  374.  
  375. PROC p_blue(x,y,c:PTR TO planeFunc_data) IS Pi96ReadPixel(c.rp,e_mod(x,c.width),e_mod(y,c.height)) AND $FF
  376. PROC q_blue(x,y,c:PTR TO planeFunc_data) IS (Pi96ReadPixel(c.rp,e_mod(!x!,c.width),e_mod(!y!,c.height)) AND $FF)!
  377.  
  378. /* Expression class. This is equivalent to the old function one. Decoding is now put in the constructor (=> a little bit less code ;)
  379. If there's a problem while decoding, the function will get f(x,y)=0*/
  380.  
  381. EXPORT SET NEEDX,SHORT -> short is x,y,e,pi,numeric-constant, i.e. what does not need computation.
  382. EXPORT ENUM FAILURE=$100,ERR_NoParse,ERR_NoFunc,ERR_NoChar
  383. EXPORT SET WARN_NoSupport,WARN_EPi
  384.  
  385. EXPORT OBJECT expression
  386.     func:PTR TO function
  387.     arg1:PTR TO expression
  388.     arg2:PTR TO expression
  389.     cte:LONG -> third arg. For reason of backward compatibility, it is the arg #1 in the expression string, when present.
  390.  
  391.     precision
  392.     evaluate -> evaluate THIS proc.
  393.  
  394.     /*precalculation stuff*/
  395. /*following: allocated with AllocVec()!!!!*/
  396.     precalc:PTR TO LONG         -> pre-calculates. Values put in buffer (only in main expr)
  397.     calculate:PTR TO LONG       -> calculates function value (only in main expr)
  398.     buffer:PTR TO LONG          -> pre-calculated value (only in main expr)
  399.  
  400.     message -> how last decoding went: WARN_#? or ERR_#? or NIL
  401.  
  402.     need:LONG -> what vars are required to eval. it
  403. ->    value:LONG -> precalculated value
  404. ENDOBJECT
  405.  
  406. /*EXPORT OBJECT outinfo
  407.     error:LONG
  408.     quote:PTR TO CHAR
  409. ENDOBJECT*/
  410.  
  411. PROC setfunc(address:PTR TO function) OF expression
  412.     self.func:=address
  413.     IF self.precision = OUT_Integer
  414.         self.evaluate:=self.func.evalI
  415.     ELSEIF self.precision = OUT_Float32
  416.         self.evaluate:=self.func.evalF
  417.     ELSE -> Actually this happens when using a non-direct output mode (copy, old,..?)
  418. ->        WriteF('Unknown output mode\n')
  419.         self.evaluate:=self.func.evalI -> (Just in case of problem, but it shouldn't be useful)
  420.     ENDIF
  421. ENDPROC
  422.  
  423. /* A Little But Serious change done here: start is the first char to decode, but end is the last plus one. (It made code a little simpler)*/
  424. PROC create(precision,input:PTR TO CHAR,start=0,end=-1,first=TRUE) OF expression HANDLE
  425. DEF currfunc:PTR TO ln,name:PTR TO CHAR,ee:PTR TO expression,
  426.     open,close,nxt:PTR TO LONG,dest:PTR TO LONG,fnc,out=NIL ->:PTR TO outinfo
  427.  
  428.     self.precision:=precision
  429.  
  430.     IF end=-1
  431.         end:=StrLen(input)
  432.         mc:=0;bs:=0
  433.     ENDIF
  434.  
  435.     IF start=end -> Empty expressions => constant zero
  436.         self.setfunc(fconstant)
  437.         self.cte:=0
  438.         JUMP toEnd
  439.     ENDIF
  440.  
  441.     IF input[start] = "(" -> If the whole expression is surrounded by brackets, decode inside.
  442.         IF findseparator(input,start,')') = (end-1)
  443.             self.create(precision,input,start+1,end-1,first)
  444.             JUMP toEnd
  445.         ENDIF
  446.     ENDIF
  447.  
  448.     /* Let's seek x_y operators */
  449.  
  450.     currfunc:=firstb
  451.     REPEAT
  452.         nxt:=findseparator(input,start-1,currfunc.name)
  453.         IF (nxt<>-1) AND (nxt<end)
  454.             self.setfunc(currfunc-4) ->!!! There's a four-bytes gap between function and ln (because function is not simply an object: it's a class :-)
  455.             NEW self.arg1.create(precision,input,start,nxt,FALSE)
  456.             out:=out OR self.arg1.message -> Gather eventual warning..
  457.             count++;mc:=Max(mc,count)
  458.             NEW self.arg2.create(precision,input,nxt+1,end,FALSE)
  459.             out:=out OR self.arg2.message
  460.             self.need:=self.arg1.need OR self.arg2.need AND Not(SHORT)
  461.             count--
  462.             JUMP toEnd
  463.         ENDIF
  464.  
  465.         currfunc:=currfunc.succ
  466.     UNTIL (currfunc = lastb.succ) OR CtrlC()
  467.     /* Now look for f() functions */
  468.  
  469.     open:=InStr(input,'(',start)
  470.     IF (open=-1) OR (open >= end) -> No () in expression, let's treat it as a whole
  471.         IF StrCmp(input+start,'x',1)
  472.             self.setfunc(fvariable)
  473.             self.cte:=VAR_x
  474.             IF end<>(start+1) THEN Throw(ERR_NoParse,input)
  475.             self.need:=NEEDX OR SHORT
  476.         ELSEIF StrCmp(input+start,'y',1)
  477.             self.setfunc(fvariable)
  478.             self.cte:=VAR_y
  479.             IF end<>(start+1) THEN Throw(ERR_NoParse,input)
  480.             self.need:=SHORT
  481.         ELSEIF StrCmp(input+start,'e',1)
  482.             self.setfunc(fconstant)
  483.             IF self.precision=OUT_Integer
  484.                 self.cte:=3
  485.                 out:=out OR WARN_EPi
  486.             ELSE
  487.                 self.cte:=2.71828183
  488.             ENDIF
  489.             IF end<>(start+1) THEN Throw(ERR_NoParse,input)
  490.             self.need:=SHORT
  491.         ELSEIF StrCmp(input+start,'pi',2)
  492.             self.setfunc(fconstant)
  493.             IF self.precision = OUT_Integer
  494.                 self.cte:=3
  495.                 out:=out OR WARN_EPi
  496.             ELSE
  497.                 self.cte:=3.14159265
  498.             ENDIF
  499.             IF end<>(start+2) THEN Throw(ERR_NoParse,input)
  500.             self.need:=SHORT
  501.         ELSE
  502.             self.setfunc(fconstant)
  503.             IF self.precision=OUT_Integer
  504.                 open,close:=Val(input+start)
  505.             ELSE
  506.                 open,close:=RealVal(input+start)
  507.             ENDIF
  508.             self.cte:=open -> putting multiple return values in objects (x.y) is not accepted...
  509.             IF close <> (end-start) THEN Throw(ERR_NoParse,input)
  510.             self.need:=SHORT
  511.         ENDIF
  512.     ELSE
  513.         IF open=start THEN -> THEN in cases like '(a)(b)', or '(a))'
  514.             Throw(ERR_NoParse,input)
  515.  
  516.         name:=String(open-start)
  517.         MidStr(name,input,start)
  518.         fnc:=FindName(lastb.pred,name) -> .pred because abs must also be found
  519.         IF fnc=NIL THEN Throw(ERR_NoFunc,name)
  520.         self.setfunc(fnc-4)
  521.         IF self.func.argcount>1
  522.             close:=findseparator(input,open,',')
  523.             IF (close=-1) OR (close>=end) THEN Throw(ERR_NoChar,',')
  524.             IF self.func.argcount>2 -> In this case, read cte,arg1,arg2
  525.  
  526.                 self.cte:=Val(input+open+1) -> Second return value: # of read chars. For error handling.
  527.                 IF self.func.readpid -> This is a project id
  528.                     self.cte:=gtd(dat,self.cte)
  529.                 ELSEIF self.precision=OUT_Float32 -> Not used for now, but may come once :-)
  530.                     self.cte:=RealVal(input+open)
  531.                 ENDIF
  532.  
  533.                 open:=close
  534.                 close:=findseparator(input,open,',')
  535.                 IF (close=-1) OR (close>=end) THEN Throw(ERR_NoChar,',')
  536.                 NEW self.arg1.create(precision,input,open+1,close,FALSE)
  537.                 self.need:=self.arg1.need AND Not(SHORT)
  538.                 count++;mc:=Max(mc,count)
  539.  
  540.  
  541.                 open:=close
  542.                 close:=findseparator(input,open,')')
  543.                 IF (close=-1) OR (close>=end) THEN Throw(ERR_NoChar,')')
  544.                 NEW self.arg2.create(precision,input,open+1,close,FALSE)
  545.                 self.need:=self.need OR self.arg2.need AND Not(SHORT)
  546.  
  547.                 count--  -> storage not needed anymore.
  548.  
  549.             ELSE -> two args
  550.                 NEW self.arg1.create(precision,input,open+1,close,FALSE)
  551.                 self.need:=self.arg1.need AND Not(SHORT)
  552.                 count++;mc:=Max(mc,count)
  553.                 open:=close
  554.                 close:=findseparator(input,open,')') 
  555.                 IF (close=-1) OR (close>=end) THEN Throw(ERR_NoChar,')')
  556.                 NEW self.arg2.create(precision,input,open+1,close,FALSE)
  557.                 self.need:=self.need OR self.arg2.need AND Not(SHORT)
  558.                 count-- -> storage not needed anymore.
  559.  
  560.                 ->WriteF('Two args function; args @ ($\h;$\h)\n',self.arg1,self.arg2)
  561.  
  562.             ENDIF
  563.             out:=out OR self.arg2.message
  564.  
  565.         ELSE -> Single arg
  566.             close:=findseparator(input,open,')')
  567.             IF (close=-1) OR (close>=end) THEN Throw(ERR_NoChar,')')
  568.             NEW self.arg1.create(precision,input,open+1,close,FALSE)
  569.             self.need:=self.arg1.need AND Not(SHORT)
  570.         ENDIF
  571.         out:=out OR self.arg1.message
  572.         IF self.evaluate={e_constant} THEN -> I assume that if a function with args is constant, then there's a problem...
  573.             out:=out OR WARN_NoSupport
  574.     ENDIF
  575. toEnd:
  576. EXCEPT DO
  577.     IF exception
  578.         IF Not(first) THEN Throw(exception,exceptioninfo)
  579.         /*NEW out
  580.         out.error:= exception;out.quote:=exceptioninfo*/
  581.         out:=/*out OR */exception -> Once there will be some more error information sent...
  582.         self.end()
  583.         self.create(self.precision,'')
  584.     ENDIF
  585.     IF self.need AND NEEDX
  586.         ->WriteF('We need x.\n')
  587.         IF self.arg1 ->THEN
  588.             ->WriteF('a -> $\h\n',self.arg1.need)
  589.             IF (self.arg1.need AND NEEDX) = $0-> THEN
  590.                 ->WriteF('Raising for a.\n')
  591.                 bs++
  592.             ENDIF
  593.         ENDIF
  594.         IF self.arg2 ->THEN
  595.             ->WriteF('b -> $\h\n',self.arg2.need)
  596.             IF (self.arg2.need AND NEEDX) = $0 ->THEN
  597.                 ->WriteF('Raising for b.\n')
  598.                 bs++
  599.             ENDIF
  600.         ENDIF
  601.     ELSEIF first -> x *never* used in whole expression: use one buffer slot.
  602.         ->WriteF('resetting bs to 1\n')
  603.         bs:=1
  604.     ENDIF
  605.  
  606.  
  607.     IF first ->THEN
  608.         ->WriteF('Code for \a\s\a\n¯¯¯¯¯ ¯ ¯ ¯\n',input)
  609.         ->kputfmt('Precalc for \a\s\a\n¯¯¯¯¯ ¯ ¯ ¯\n',[input])
  610.         self.compile((end-start)*10+32,mc,bs) -> Be sure that there's enough room in string :-)
  611.     ENDIF
  612.     self.message:=out
  613. ENDPROC
  614.  
  615. /* find first separator (sep: ')', ',', or '+', .....) following index, in input */
  616. PROC findseparator(input:PTR TO CHAR,index,sep)
  617. DEF open,nxt
  618.     open:=InStr(input,'(',index+1)
  619.     IF open=-1 THEN open:=StrLen(input)
  620.     nxt:=InStr(input,sep,index+1)
  621.     IF nxt < open THEN RETURN nxt
  622.  
  623.     /* nxt > open */
  624.     nxt:=findseparator(input,open,')') -> Where does that "open" close?
  625.     IF nxt=-1 THEN Throw(ERR_NoChar,')') -> If it doesn't => error
  626. ENDPROC findseparator(input,nxt,sep) -> If it does, let's return the following sep
  627.  
  628. /* Reg usage: A5 is for temporary values, valid during one single expr evaluation;
  629.               A1 points to the pre-calculated values*/
  630.  
  631. PROC compile(len,maxcount,buffsize) OF expression
  632. DEF nxt:PTR TO LONG,dest:PTR TO LONG
  633.     c:=0;p:=0;s:=-1
  634.     NEW code[len];crs:=code
  635.     NEW precalc[len];prs:=precalc
  636. ->WriteF('Allocating buffer [$\h*4] ;-> A1\n',buffsize+1)
  637.     buffer:=AllocVec(buffsize*4+4,MEMF_PUBLIC) -> 4 is SIZEOF LONG
  638.     self.buffer:=buffer
  639.  
  640. ->WriteF('LINK A5,#$\h\n',(-maxcount-2)*4 AND $FFFF)
  641.     crs[]:=$4E55;crs++; crs[]:=(-maxcount-2)*4 AND $FFFF;crs++ -> LINK A5,#$<..maxcount..>
  642. ->  crs[]:=$227C;crs++; crs[]:=Shr(buffer,16);crs++; crs[]:=buffer;crs++ ->MOVE.L buffer,A1
  643.  
  644. ->kputfmt('LINK A5,#$\h\n',[(-maxcount-2)*4 AND $FFFF])
  645.     prs[]:=$4E55;prs++; prs[]:=(-maxcount-2)*4 AND $FFFF;prs++ -> LINK A5,#$<maxcount>
  646.  
  647. ->  prs[]:=$227C;prs++; prs[]:=Shr(buffer,16);prs++; prs[]:=buffer;prs++ ->MOVE.L buffer,A1
  648.  
  649.     self.subcompile()
  650.     IF (self.need AND NEEDX)=$0 -> If *nothing* in the expression depends on x, let's save+recall here.
  651.         s++
  652.  
  653. ->WriteF('MOVE.L #$\h,A1\n',buffer)
  654.         crs[]:=$227C;crs++; crs[]:=Shr(buffer,16);crs++; crs[]:=buffer;crs++ ->MOVE.L buffer,A1
  655. ->kputfmt('MOVE.L #$\h,A1\n',[buffer])
  656.         prs[]:=$227C;prs++; prs[]:=Shr(buffer,16);prs++; prs[]:=buffer;prs++ ->MOVE.L buffer,A1
  657.  
  658. ->kputfmt('MOVE.L D0,\h(A1)\n',[s*4])
  659.         prs[]:=$2340;prs++;prs[]:=s*4;prs++ -> MOVE.L D0,<s*4>(A1)
  660. ->WriteF('MOVE.L \h(A1),D0)\n',s*4)
  661.         crs[]:=$2029;crs++;crs[]:=s*4;crs++ -> MOVE.L <s*4>(A1),D0
  662.     ENDIF
  663.  
  664. ->WriteF('UNLK A5\nRTS\n\nResulting code:')
  665.     crs[]:=$4E5D;crs++ -> UNLK A5
  666.     crs[]:=$4E75;crs++ -> RTS
  667.  
  668. ->kputfmt('UNLK A5\nRTS\n\nResulting code:',[])
  669.     prs[]:=$4E5D;prs++ -> UNLK A5
  670.     prs[]:=$4E75;prs++ -> RTS
  671.  
  672.     self.calculate:=AllocVec(crs-code+16,NIL)
  673.     nxt:=code;dest:=self.calculate
  674.     WHILE nxt <= (crs)
  675.         ->WriteF('\z\h[8]',nxt[])
  676.         dest[]:=nxt[]
  677.         nxt++;dest++
  678.     ENDWHILE
  679.     ->WriteF('\n')
  680.     ->WriteF('calc at $\h+$\h ',self.calculate,crs-code)
  681.     END code[len]
  682.  
  683.     self.precalc:=AllocVec(prs-precalc+16,NIL)
  684.     nxt:=precalc;dest:=self.precalc
  685.     WHILE nxt <= (prs)
  686.         ->kputfmt('\z\h[8]',[nxt[]])
  687.         dest[]:=nxt[]
  688.         nxt++;dest++
  689.     ENDWHILE
  690.     ->kputfmt('\n',[])
  691.     ->WriteF('and precalc at $\h+$\h.\n',self.precalc,prs-precalc)
  692.     END precalc[len]
  693. ENDPROC
  694.  
  695. PROC long(k:PTR TO expression)
  696.     IF k
  697.         RETURN (k.need AND SHORT) = $0
  698.     ELSE
  699.         RETURN FALSE
  700.     ENDIF
  701. ENDPROC
  702.  
  703. PROC subcompile() OF expression
  704. DEF saved=FALSE, -> TRUE if arg1 was saved in A5.
  705.     buff=-1  -> buffer-slot (in case "f(y)_f(x)") where f(y) is stored
  706.     IF long(self) = FALSE -> That's only if the global (whole) expression is short.
  707.         ->WriteF('The global expression is short.\n')
  708.         IF self.func=fvariable -> For now, use pre-calculation as usual, I mean, 'y' expression will be pre-calculated even if it is quite useless...
  709.            IF self.cte=VAR_x
  710.                ->WriteF('MOVE.L $C(A5),D0\n')
  711.                crs[]:=$202D;crs++ -> MOVE.L $C(A5),D0
  712.                crs[]:=$C;crs++
  713.            ELSEIF self.cte=VAR_y
  714.                ->kputfmt('MOVE.L $8(A5),D0\n',[])
  715.                prs[]:=$202D;prs++ -> MOVE.L $8(A5),D0
  716.                prs[]:=$8;prs++
  717.            ENDIF
  718.        ELSEIF self.func=fconstant
  719.             ->kputfmt('MOVE.L #$\h,D0\n',[self.cte])
  720.            prs[]:=$203C ;prs++ -> MOVE.L #self.cte,D0
  721.            prs[]:=Shr(self.cte,16);prs++;prs[]:=self.cte ;prs++ -> constant argument
  722.        ENDIF
  723.        RETURN
  724.     ENDIF
  725. ->WriteF('[...\n')
  726. ->kputfmt('[...\n',[])
  727.  
  728. /* First of all calculate subexpressions that need to be calculated */
  729.     IF long(self.arg1)
  730.         self.arg1.subcompile()
  731.         IF long(self.arg2) -> If we have two args that need computation, then we'll have to save one to do the other one...
  732.             IF self.arg1.need AND NEEDX -> Neither arg1, nor us can pre-calculate.
  733.                 c++
  734.                 ->WriteF('MOVE.L D0,$-\h(A5)\n',c*4)
  735.                 crs[]:=$2B40;crs++-> MOVE.L D0,$-<c*4>(A5)
  736.                 crs[]:=-c*4 ;crs++-> store that arg
  737.                 saved:=TRUE
  738.             ELSEIF (self.need AND NEEDX) = $0
  739.                 p++
  740.                 ->kputfmt('MOVE.L D0,$-\h(A5)\n',[p*4])
  741.                 prs[]:=$2B40;prs++-> MOVE.L D0,$-<p*4>(A5)
  742.                 prs[]:=-p*4 ;prs++-> store that arg
  743.                 saved:=TRUE
  744.             ENDIF
  745.         ENDIF
  746.         ->WriteF('self:$\h;self.arg1:$\h\n',self.need,self.arg1.need)
  747.         IF self.need AND Not(self.arg1.need) AND NEEDX -> save pre-calculated arg1 to A1
  748.             s++
  749.             buff:=s
  750.             ->kputfmt('MOVE.L $\h,A1\n',[buffer])
  751.             prs[]:=$227C;prs++;prs[]:=Shr(buffer,16);prs++; prs[]:=buffer;prs++ ->MOVE.L buffer,A1
  752.             ->kputfmt('MOVE.L D0,$\h(A1)\n',[s*4])
  753.             prs[]:=$2340;prs++;prs[]:=s*4;prs++ -> MOVE.L D0,<s*4>(A1)
  754.         ENDIF
  755.     ENDIF
  756.     IF long(self.arg2)
  757.         self.arg2.subcompile()
  758.         IF self.need AND Not(self.arg2.need) AND NEEDX -> arg2 doesn't needx but we do => save pre-calculated arg2 to A1
  759.             s++
  760.             ->kputfmt('MOVE.L $\h,A1\n',[buffer])
  761.             prs[]:=$227C;prs++;prs[]:=Shr(buffer,16);prs++; prs[]:=buffer;prs++ ->MOVE.L buffer,A1
  762.             ->kputfmt('MOVE.L D0,$\h(A1)\n',[s*4])
  763.             prs[]:=$2340;prs++;prs[]:=s*4;prs++ -> MOVE.L D0,<s*4>(A1)
  764.         ENDIF
  765.     ENDIF
  766.  
  767. /* Now put arguments in stack and execute function. */
  768.     IF long(self.arg1)=FALSE -> I assume that self.arg1 exists
  769.         IF self.arg1.func=fvariable
  770.             IF self.arg1.cte=VAR_x
  771.                 ->WriteF('MOVE.L $C(A5),-(A7)\n')
  772.                 crs[]:=$2F2D;crs++ -> MOVE.L $C(A5),-(A7)
  773.                 crs[]:=$C;crs++
  774.             ELSEIF self.arg1.cte=VAR_y
  775.                 ->WriteF('MOVE.L $8(A5),-(A7)\n');->kputfmt('MOVE.L $8(A5),-(A7)\n',[])
  776.                 write($2F2D,self.need) -> MOVE.L $8(A5),-(A7)
  777.                 write($8,self.need) -> "write", as we wouldn't need pre-calculation if there's only a single y.
  778.             ENDIF
  779.         ELSEIF self.arg1.func=fconstant
  780.             ->WriteF('MOVE.L #$\h,D0\n',self.arg1.cte);->kputfmt('MOVE.L #$\h,D0\n',[self.arg1.cte])
  781.             write($2F3C,self.need) -> MOVE.L #self.cte,-(A7)
  782.             write(Shr(self.arg1.cte,16),self.need);write(self.arg1.cte,self.need)
  783.         ENDIF
  784.     ELSEIF saved
  785.         IF self.need AND NEEDX
  786.             ->WriteF('MOVE.L $-\h(A5),-(A7)\n',c*4)
  787.             crs[]:=$2F2D ;crs++ -> MOVE.L $-<c*4>(A5),-(A7)
  788.             crs[]:=-c*4 ;crs++-> push copied argument (a)
  789.             c--
  790.         ELSE
  791.             ->kputfmt('MOVE.L $-\h(A5),-(A7)\n',[p*4])
  792.             prs[]:=$2F2D ;prs++ -> MOVE.L $-<p*4>(A5),-(A7)
  793.             prs[]:=-p*4 ;prs++-> push copied argument (a)
  794.             p--
  795.         ENDIF
  796.     ELSEIF buff>-1 -> Copy pre-calculated value.
  797.         ->WriteF('MOVE.L #$\h,A1\n',buffer)
  798.         crs[]:=$227C;crs++;crs[]:=Shr(buffer,16);crs++; crs[]:=buffer;crs++ ->MOVE.L buffer,A1
  799.         ->WriteF('MOVE.L $\h(A1),-(A7)\n',buff*4)
  800.         crs[]:=$2F29;crs++ -> MOVE.L <buff*4>(A1),-(A7)
  801.         crs[]:=buff*4;crs++
  802.     ELSE -> Long arg1(x), Short arg2
  803.         ->WriteF('Long arg1(x), Short arg2; buff is \d\n',buff)
  804.         IF self.need AND NEEDX
  805.             ->WriteF('MOVE.L D0,-(A7)\n')
  806.             crs[]:=$2F00 ;crs++ -> MOVE.L D0,-(A7)
  807.         ELSE
  808.             ->kputfmt('MOVE.L D0,-(A7)\n',[])
  809.             prs[]:=$2F00 ;prs++ -> MOVE.L D0,-(A7)
  810.         ENDIF
  811.     ENDIF
  812.  
  813.     IF self.arg2
  814.         IF long(self.arg2)
  815.             IF self.need AND NEEDX
  816.                 IF self.arg2.need AND NEEDX
  817.                     ->WriteF('MOVE.L D0,-(A7)\n')
  818.                     crs[]:=$2F00 ;crs++ -> MOVE.L D0,-(A7)
  819.                 ELSE
  820.                     ->WriteF('MOVE.L #$\h,A1\n',buffer)
  821.                     crs[]:=$227C;crs++;crs[]:=Shr(buffer,16);crs++; crs[]:=buffer;crs++ ->MOVE.L buffer,A1
  822.                     ->WriteF('MOVE.L $\h(A1),-(A7)\n',s*4)
  823.                     crs[]:=$2F29;crs++ -> MOVE.L <s*4>(A1),-(A7)
  824.                     crs[]:=s*4;crs++
  825.                 ENDIF
  826.             ELSE
  827.                 ->kputfmt('MOVE.L D0,-(A7)\n',[])
  828.                 prs[]:=$2F00 ;prs++ -> MOVE.L D0,-(A7)
  829.             ENDIF
  830.         ELSE
  831.             IF self.arg2.func=fvariable
  832.                 IF self.arg2.cte=VAR_x
  833.                     ->WriteF('MOVE.L $C(A5),-(A7)\n')
  834.                     crs[]:=$2F2D;crs++ -> MOVE.L $C(A5),-(A7)
  835.                     crs[]:=$C;crs++
  836.                 ELSEIF self.arg2.cte=VAR_y
  837.                     ->WriteF('MOVE.L $8(A5),-(A7)\n');->kputfmt('MOVE.L $8(A5),-(A7)\n',[])
  838.                     write($2F2D,self.need) -> MOVE.L $8(A5),-(A7)
  839.                     write($8,self.need) -> "write", as we wouldn't need pre-calculation if there's only a single y.
  840.                 ENDIF
  841.             ELSEIF self.arg2.func=fconstant
  842.                 ->WriteF('MOVE.L #$\h,-(A7)\n',self.arg2.cte);->kputfmt('MOVE.L #$\h,-(A7)\n',[self.arg2.cte])
  843.                 write($2F3C,self.need) -> MOVE.L #self.arg2.cte,-(A7)
  844.                 write(Shr(self.arg2.cte,16),self.need);write(self.arg2.cte,self.need) -> constant argument
  845.             ENDIF
  846.         ENDIF
  847.     ELSE -> No arg2: push zero
  848.         ->WriteF('MOVE.L #0,-(A7)\n');->kputfmt('MOVE.L #0,-(A7)\n',[])
  849.         write($2F3C,self.need) -> MOVE.L #0,-(A7)
  850.         write(0,self.need);write(0,self.need)
  851.     ENDIF
  852.     IF self.need AND NEEDX
  853.         ->WriteF('MOVE.L #$\h,-(A7)\n',self.cte)
  854.         crs[]:=$2F3C ;crs++ -> MOVE.L #self.cte,-(A7)
  855.         crs[]:=Shr(self.cte,16);crs++;crs[]:=self.cte ;crs++
  856.         ->WriteF('JSR \s\n',self.func.ln.name)
  857.         crs[]:=$4EB9 ;crs++ -> JSR self.evaluate
  858.         crs[]:=Shr(self.evaluate,16);crs++;crs[]:=self.evaluate ;crs++
  859.     ELSE
  860.         ->kputfmt('MOVE.L #$\h,-(A7)\n',[self.cte])
  861.         prs[]:=$2F3C ;prs++ -> MOVE.L #self.cte,-(A7)
  862.         prs[]:=Shr(self.cte,16);prs++;prs[]:=self.cte ;prs++
  863.         ->kputfmt('JSR \s\n',[self.func.ln.name])
  864.         prs[]:=$4EB9 ;prs++ -> JSR self.evaluate
  865.         prs[]:=Shr(self.evaluate,16);prs++;prs[]:=self.evaluate ;prs++
  866.     ENDIF
  867. ->WriteF('...]\n')
  868. ->kputfmt('...]\n',[])
  869. ENDPROC
  870.  
  871. PROC write(value,need) -> Little loss of time here at pre-compilation-time, but it is nicer so.
  872.     IF need AND NEEDX
  873.         crs[]:=value;crs++
  874. ->kputfmt('Oh, sorry, I made a mistake: The above command is not executed (sorry;-)\n',[])
  875.     ELSE
  876.         prs[]:=value;prs++
  877. ->WriteF('Oh, sorry, I made a mistake: The above command is not executed (sorry;-)\n')
  878.     ENDIF
  879. ENDPROC
  880.  
  881. PROC reference() OF expression
  882.     IF self.func.readpid = TRUE THEN -> I guess that all function that need a data require having its project frozen...
  883.         RETURN self.cte,self.arg1,self.arg2
  884. ENDPROC self.func.argcount+1,self.arg1,self.arg2
  885.  
  886. PROC evaluate(x,y) OF expression
  887. DEF a,b,p
  888.     IF self.func=fvariable
  889.         p:=self.evaluate
  890.         RETURN p(x,y,self.cte)
  891.     ENDIF
  892.     IF self.func.argcount>0
  893.         a:=self.arg1.evaluate(x,y)
  894.         IF self.func.argcount>1 ->THEN
  895.             b:=self.arg2.evaluate(x,y)
  896.         ENDIF
  897.     ENDIF
  898.     p:=self.evaluate
  899. ENDPROC p(a,b,self.cte)
  900.  
  901. PROC end() OF expression
  902.     IF self.func -> Maybe the decoding was aborted before we could know the function...
  903.         IF self.func.argcount>0
  904.             END self.arg1
  905.             IF self.func.argcount>1 THEN END self.arg2
  906.         ENDIF
  907.     ENDIF
  908.     IF self.calculate THEN
  909.         FreeVec(self.calculate)
  910.     IF self.precalc THEN
  911.         FreeVec(self.precalc)
  912.     IF self.buffer THEN
  913.         FreeVec(self.buffer)
  914.  
  915. ENDPROC
  916.  
  917. ->EXPORT a4storage: LONG NIL
  918.